package com.lc.rocketmq.service;

import com.lc.rocketmq.common.Constants;
import com.lc.rocketmq.po.Order;
import com.lc.rocketmq.vo.SeckillVo;
import com.lc.rocketmq.vo.WaitingPayVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author liuc
 * @date 2021/8/21
 * @description
 **/
@Service
@Slf4j
public class SeckillService {
    //缓存 标识商品是否剩余库存
    private Map<Long,Boolean> stockMap = new HashMap<>();
    private final Object PLACE_HOLDER = new Object();
    //下单成功的用户缓存
    private Map<String,Object> secskillOrderMap = new HashMap<>();
    //秒杀成功的用户缓存
    private Map<String,Object> secskillSucMap = new HashMap<>();

    @Autowired
    private RedisService redisService;
    @Autowired
    private SeckillSender seckillSender;
    @Autowired
    private OrderService orderService;

    public void fillStockMap(Long id){
        stockMap.put(id,true);
    }

    //秒杀逻辑
    public String doSeckill(SeckillVo vo){
        //todo 流控
        // 是否到了秒杀时间
        if(!check(vo)){
            return "请求参数异常";
        }
        final Long goodsId = vo.getGoodsId();
        final Long userId = vo.getUserId();
        String key = userId+"_"+goodsId;
        //todo 存放在redis中, 过期时间为秒杀时间
        if(secskillSucMap.get(key) != null){
            log.warn("just can buy once!");
            return "只能抢购一次";
        }
        if(!stockMap.containsKey(goodsId)){
            return "商品不存在";
        }
        long incr = redisService.incr(Constants.GOODS_PREFIX + goodsId, -1);
        if(incr < 0){
            //log.warn("sell out!");
            sellout(goodsId);
            return "抢购失败";
        }
        log.info("sec kill success, user id:{}",userId);
        seckillSender.seckill(vo);
        orderSuccess(vo,PLACE_HOLDER);
        return "ok";
    }

    public boolean check(SeckillVo vo){
        Long goodsId = vo.getGoodsId();
        Long userId = vo.getUserId();
        if(goodsId == null || userId == null || vo.getToken() == null){
            log.warn("no goods id or no user id or no token");
            return false;
        }
        return true;
//        String key = tokenKey(vo);
//        String token = redisService.get(key);
//        return vo.getToken().equals(token);
    }

    //设置售卖完
    public void sellout(Long goodsId){
        stockMap.put(goodsId,false);
    }

    //恢复
    public void recovery(Long userId, Long goodsId, int stock){
        //恢复数据
        log.info("恢复数据, goodsId:{}, stock:{}",goodsId,stock);
        stockMap.put(goodsId,true);
        String key = userId+"_"+goodsId;
        secskillOrderMap.remove(key);
        redisService.set(Constants.GOODS_PREFIX + goodsId,String.valueOf(stock),-1);
    }



    //下单成功
    public void orderSuccess(SeckillVo vo, Object orderId){
        record(vo, secskillOrderMap, orderId);
    }

    //成功秒杀,支付完成
    public void paySuccess(SeckillVo vo){
        record(vo, secskillSucMap, PLACE_HOLDER);
    }

    //记录缓存
    private void record(SeckillVo vo, Map<String, Object> secskillSucMap, Object o) {
        final Long goodsId = vo.getGoodsId();
        final Long userId = vo.getUserId();
        if(goodsId == null || userId == null){
            log.warn("no goods id or no user id");
            return;
        }
        String key = userId+"_"+goodsId;
        secskillSucMap.put(key,o);
    }

    //记录缓存
    private boolean hasRecord(SeckillVo vo, Map<String, Object> secskillSucMap) {
        return getRecord(vo,secskillSucMap) != null;
    }

    //获取缓存
    private Object getRecord(SeckillVo vo, Map<String, Object> secskillSucMap) {
        final Long goodsId = vo.getGoodsId();
        final Long userId = vo.getUserId();
        if(goodsId == null || userId == null){
            log.warn("no goods id or no user id");
            return false;
        }
        String key = userId+"_"+goodsId;
        return secskillSucMap.get(key);
    }

    public String result(SeckillVo vo) {
        //查看秒杀的结果
        Object record = getRecord(vo, secskillSucMap);
        if(record != null){
            return "秒杀成功";
        }
        Object orderId = getRecord(vo, secskillOrderMap);
        if(orderId == PLACE_HOLDER){
            return "订单排队中";
        }
        if(orderId != null){
            return orderId.toString();
        }
        return "秒杀失败";
    }

    public String token(SeckillVo vo) {
        //获取token
        if(!stockMap.containsKey(vo.getGoodsId())){
            log.warn("no goods found!");
            return null;
        }
        String key = tokenKey(vo);
        String token = Md5Crypt.md5Crypt(key.getBytes());
        redisService.set(key,token,60);
        return token;
    }

    private String tokenKey(SeckillVo vo){
        return "token:u:"+vo.getUserId()+":g:"+vo.getGoodsId();
    }

    //支付
    @Transactional(rollbackFor = Exception.class)
    public String pay(WaitingPayVo vo) {
        Order order = orderService.get(vo.getOrderId());
        Date date = new Date();
        if(order == null){
            return "订单不存在";
        }
        //大于30秒的订单则设置支付过期
        if(date.getTime() - order.getCreateTime().getTime() > 30000){
            orderService.timeout(vo.getOrderId());
            return "订单支付已过期,请重新下单";
        }
        boolean b = orderService.pay(vo.getOrderId());
        if(b){
            SeckillVo seckillVo = new SeckillVo();
            seckillVo.setUserId(vo.getUserId());
            seckillVo.setGoodsId(vo.getGoodsId());
            paySuccess(seckillVo);
            return "支付成功";
        }else{
           order = orderService.get(vo.getOrderId());
           if(order.getStatus() == 2){
               return "支付过期";
           }else{
               return "订单失效";
           }
        }
    }
}
